Add bounds checking on buffer_idx for constant_buffer and constant_data in XNNPACK#18820
Add bounds checking on buffer_idx for constant_buffer and constant_data in XNNPACK#18820
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/18820
Note: Links to docs will display an error until the docs builds have been completed. ❗ 1 Active SEVsThere are 1 currently active SEVs. If your PR is affected, please view them below: ⏳ No Failures, 5 PendingAs of commit 4e15ca5 with merge base 5e8a0df ( This comment was automatically generated by Dr. CI and updates every 15 minutes. |
This PR needs a
|
There was a problem hiding this comment.
Pull request overview
Adds bounds validation for buffer_idx when resolving constant tensor data in the XNNPACK flatbuffer path, preventing out-of-range access into constant_buffer / constant_data.
Changes:
- Add null + bounds checks for
flatbuffer_graph->constant_buffer()before indexing. - Add null + bounds checks for
flatbuffer_graph->constant_data()before callingGet(buffer_idx). - Emit error logs and return
nullptron invalid indices.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (cb == nullptr || buffer_idx >= cb->size()) { | ||
| ET_LOG( | ||
| Error, | ||
| "Invalid buffer_idx %u for constant_buffer of size %u", | ||
| buffer_idx, | ||
| cb ? cb->size() : 0); | ||
| return nullptr; | ||
| } |
There was a problem hiding this comment.
Returning nullptr on an out-of-bounds/nonexistent buffer_idx conflates “non-constant tensor” (buffer_idx==0) with “corrupt/invalid flatbuffer” (buffer_idx!=0 but invalid). Callers like defineTensor pass the returned pointer directly into xnn_define_tensor_value; with a non-zero constant_buffer_idx this can silently create an internal (non-constant) tensor instead of failing fast. Consider changing getConstantDataPtr to return a Result<const uint8_t*> (or add an explicit error flag) so invalid indices propagate as an Error, or at minimum enforce that buffer_idx!=0 implies non-null return and surface an error upstream.
| cd ? cd->size() : 0); | ||
| return nullptr; | ||
| } | ||
| ConstantDataOffsetPtr constant_data_offset = cd->Get(buffer_idx); |
There was a problem hiding this comment.
cd->Get(buffer_idx) can still return nullptr if the vector contains a null offset (possible with corrupted input). constant_data_offset is dereferenced immediately afterward; add a null check for constant_data_offset and handle it as an invalid constant_data entry (log + propagate error).
| ConstantDataOffsetPtr constant_data_offset = cd->Get(buffer_idx); | |
| ConstantDataOffsetPtr constant_data_offset = cd->Get(buffer_idx); | |
| if (constant_data_offset == nullptr) { | |
| ET_LOG( | |
| Error, | |
| "Invalid null constant_data entry at buffer_idx %u", | |
| buffer_idx); | |
| return nullptr; | |
| } |
|
@claude review this PR |
|
Claude finished @lucylq's task in 1m 28s —— View job Review of PR #18820
The fix correctly addresses the core issue: the previous code dereferenced Two issues remain that should be addressed: 1. Missing null check after After the bounds check, const auto& constant_buffer = *cb;
auto* buffer_entry = constant_buffer[buffer_idx];
if (buffer_entry == nullptr || buffer_entry->storage() == nullptr) {
ET_LOG(Error, "Null constant_buffer entry at buffer_idx %u", buffer_idx);
return nullptr;
}
return buffer_entry->storage()->data();2. Missing null check after Similarly, ConstantDataOffsetPtr constant_data_offset = cd->Get(buffer_idx);
if (constant_data_offset == nullptr) {
ET_LOG(Error, "Null constant_data entry at buffer_idx %u", buffer_idx);
return nullptr;
}3. Caller impact of returning For the Items 1 and 2 are the higher priority since they leave crash paths open that this PR aims to close. Fix these issues → |
GregoryComer
left a comment
There was a problem hiding this comment.
Can we update defineTensor to handle the case of a nullptr returned from getConstantDataPtr? It might silently break on malformed PTE.
thanks that's a great catch - I'll wrap the return of |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| data_name.c_str(), | ||
| static_cast<uint32_t>(buffer.error())); | ||
| return nullptr; | ||
| return Error::InvalidProgram; |
There was a problem hiding this comment.
This branch discards the underlying named_data_map->get_data() error and always returns Error::InvalidProgram. Propagating buffer.error() would preserve the real failure mode (e.g., NotFound/InvalidExternalData) and make error handling/debugging more accurate.
| return Error::InvalidProgram; | |
| return buffer.error(); |
|
@claude re-review? |
|
Claude finished @lucylq's task in 59s —— View job Re-review of PR #18820
This is a solid revision that addresses all the issues from the first review. The key improvements since the last review:
One minor observation, not blocking:
Overall the PR is clean and correct. The |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| buffer_idx < cd->size(), | ||
| InvalidProgram, | ||
| "buffer_idx %u out of bounds for constant_data of size %zu", | ||
| buffer_idx, | ||
| cd->size()); |
There was a problem hiding this comment.
Same issue here: the error message uses %zu for cd->size(), but FlatBuffers vector sizes are typically uoffset_t (uint32_t). Please cast to size_t when using %zu (or use a %u-style specifier with an appropriate cast) to avoid varargs type mismatch/UB.
Add bounds checking on buffer_idx in both constant_buffer and constant_data code paths of getConstantDataPtr to prevent out-of-bounds vector access from malicious flatbuffer inputs. Authored-with: Claude
Check that buffer_idx is within bounds of
flatbuffer_graph->constant_buffer()andflatbuffer_graph->constant_data(), whichever branch is chosenAuthored-with: Claude